/**************************************************************************** 
 * Meta，一个轻量级的静态分区Hypervisor 
 *
 * 版权(c) , 2022-
 *
 * 作者:
 *      Tupelo Shen <shenwanjiang2013@163.com>
 *
 * Meta是一个自由软件，你可以在遵循GNU GPLv2协议的条件下，重新修改并发布它。
 *
 ***************************************************************************/

#ifndef __LIST_H__
#define __LIST_H__

#include <meta.h>
#include <spinlock.h>

typedef void* node_t;
struct list {
    node_t* head;
    node_t* tail;
    spinlock_t lock;
};

#define list_foreach(list, type, nodeptr)                     \
    for (type* nodeptr = ((type*)list.head); nodeptr != NULL; \
         nodeptr = *((type**)nodeptr))

#define list_foreach_tail(list, type, nodeptr, tail)                \
    for (type* nodeptr = ((type*)list.head), *tail = ((type*)list); \
         nodeptr != NULL; tail = nodeptr, nodeptr = *((type**)nodeptr))

static inline void list_init(struct list* list)
{
    if (list != NULL) {
        list->head = NULL;
        list->tail = NULL;
        list->lock = SPINLOCK_INITVAL;
    }
}

static inline void list_push(struct list* list, node_t* node)
{
    if (list != NULL && node != NULL) {
        *node = NULL;
        spin_lock(&list->lock);

        if (list->tail != NULL) *list->tail = node;

        list->tail = node;

        if (list->head == NULL) list->head = node;

        spin_unlock(&list->lock);
    }
}

static inline node_t* list_pop(struct list* list)
{
    node_t* temp = NULL;
    if (list != NULL) {
        spin_lock(&list->lock);

        if (list->head != NULL) {
            temp = list->head;
            list->head = *list->head;

            if (list->head == NULL) list->tail = NULL;

            *temp = NULL;
        }

        spin_unlock(&list->lock);
    }
    return temp;
}

static inline node_t* list_peek(struct list* list)
{
    node_t* temp = NULL;
    if (list != NULL) {
        temp = list->head;
    }
    return temp;
}

static inline bool list_empty(struct list* list)
{
    return (list->head == NULL);
}

static inline bool list_rm(struct list* list, node_t node)
{
    if (list != NULL && node != NULL) {
        spin_lock(&list->lock);

        node_t* temp = list->head;
        node_t* temp_prev = NULL;
        while (temp != NULL && temp != node) {
            temp_prev = temp;
            temp = *temp;
        }
        if (temp != NULL && temp == node) {
            /* found the node, remove it */
            *temp_prev = *temp;
        }

        spin_unlock(&list->lock);
    }

    return true;
}

#endif /* __LIST_H__ */
